import {
	appendChildToContainer,
	commitUpdate,
	Container,
	hideInstance,
	hideTextInstance,
	insertChildToContainer,
	Instance,
	removeChild,
	unhideInstance,
	unhideTextInstance
} from '../../react-dom/src/hostConfig';
import { FiberNode, FiberRootNode, PendingPassiveEffects } from './fiber';
import {
	ChildDeletion,
	Flags,
	LayoutMask,
	MutationMask,
	NoFlags,
	PassiveEffect,
	PassiveMask,
	Placement,
	Update,
	Ref,
	Visibility
} from './fiberFlags';
import { Effect, FCUpdateQueue } from './fiberHooks';
import { HookHasEffect } from './hookEffectTags';
import {
	FunctionComponent,
	HostComponent,
	HostRoot,
	HostText,
	OffscreenComponent,
	SuspenseComponent
} from './workTags';

// 该 变量的作用就是 指向下一个 需要执行的 副作用 fiber
let nextEffect: FiberNode | null = null;

export const commitEffects = (
	phrase: 'mutation' | 'layout',
	mask: Flags,
	callback: (fiber: FiberNode, root: FiberRootNode) => void
) => {
	return (finishedWork: FiberNode, root: FiberRootNode) => {
		// 这个 过程 和  beginWork 和 completeWork 很像 先向下 找 走到底了 或者 条件不符了 就判断本身 然后再 找 兄弟
		// 走到 这里 说明 fiber 树 里面 有 副作用 去找 副作用 具体 在那个 fiber 里面
		nextEffect = finishedWork;
		while (nextEffect !== null) {
			// 向下遍历
			const child: FiberNode | null = nextEffect.child;

			if ((nextEffect.subtreeFlags & mask) !== NoFlags && child !== null) {
				// 当前 fiber 有子节点，并且子节点有 需要处理的 副作用
				// 那就 继续遍历 找到 具体到 副作用 在哪个节点上
				nextEffect = child;
				// 先遍历到最深的节点 再往上遍历
			} else {
				//  走到这 说明
				//  要么 就是 当前fiber没有子节点了
				// 要么就是 子节点 的 subtreeFlags 里面没有 需要处理的副作用
				// 因为 子节点 里面 不包括 mask 对应的副作用 了 就没必要往下 再找了
				// 1.那就 看 当前fiber的节点上 flags的属性 上有对应的 副作用没
				// 2.还有 就是 要继续看 兄弟 节点 有没有 对应的 副作用呢   重复  第一层 while循环
				// 然后 就向上 看 父节点 和 父节点的 兄弟 节点 有没有 对应的 副作用 重复 1 2
				// 向上 向 兄弟节点 遍历 DFS 命名这个循环为up
				up: while (nextEffect !== null) {
					// 该方法就是去 处理  该节点是否有副作用 有的话 就去处理
					// 这个方法就是  当前fiber 本身的 flags 属性上 有对应的 副作用
					// 因为走到这 说明 当前fiber 没有子节点了 或者 子节点的 subtreeFlags 里面没有 需要处理的副作用
					callback(nextEffect, root);

					const sibling: FiberNode | null = nextEffect.sibling;

					if (sibling !== null) {
						nextEffect = sibling;
						break up; // 退出 up循环 继续外层的循环
					}
					// 如果 兄弟节点为null  则向上归  继续走 up 循环  去 变量 父节点的兄弟节点
					nextEffect = nextEffect.return;
				}
			}
		}
	};
};

// 该方法 就是 执行 每个具体 fiber 节点 mutaion阶段 要处理的副作用
// 这个方法就是  当前fiber 本身的 flags 属性上 有对应的 副作用
// 因为走到这 说明 当前fiber 没有子节点了 或者 子节点的 subtreeFlags 里面没有 需要处理的副作用
const commitMutationEffectsOnFiber = (
	finishedWork: FiberNode,
	root: FiberRootNode
) => {
	const { flags, tag } = finishedWork;
	const current = finishedWork.alternate;

	if ((flags & Placement) !== NoFlags) {
		// 说明 当前fiber 节点 有 Placement 副作用
		// 处理 Placement 副作用
		commitPlacement(finishedWork);

		finishedWork.flags &= ~Placement; // 移除掉 Placement 副作用
	}
	if ((flags & Update) !== NoFlags) {
		// 说明该阶段上存在更新
		// 根据 tag 类型去 处理更新
		commitUpdate(finishedWork);
		finishedWork.flags &= ~Update;
	}
	if ((flags & ChildDeletion) !== NoFlags) {
		// ChildDeletion这个标记 是标记在需要被删除的节点的父节点上的
		// 所以 父节点上的 subtreeFlags 是没这个标记的 所以能走到这里来
		// 走到这说明finishedWork 节点上 存在 需要被删除的 子节点
		const deletions = finishedWork.deletions;
		if (deletions !== null) {
			deletions.forEach((childToDelete) => {
				// 遍历需要删除的节点
				commitDeletion(childToDelete, root);
			});
		}
		finishedWork.flags &= ~ChildDeletion; // 清除标记
	}

	// 表明 当前fiber 节点上 存在 PassiveEffect 副作用 需要执行的
	// 将对应的 effect 收集到 root.pendingPassiveEffects 中
	if ((flags & PassiveEffect) !== NoFlags) {
		// 收集回调
		// 因为当前fiber 标记了 PassiveEffect 说明 他里面的 hook 有副作用 回调函数要执行
		// 将 fiber对应的 lastEffect 添加到 root.pendingPassiveEffects.update 里面
		// 然后 调度的时候 先 将 root.pendingPassiveEffects.update 里面的 effect标记有 Passive ｜ HookHasEffect 的  effect的 destroy 执行一遍
		//然后 再 将 root.pendingPassiveEffects.update 里面的 effect标记有 Passive ｜ HookHasEffect 的  effect的 create 执行一遍
		commitPassiveEffect(finishedWork, root, 'update'); // 这里子fiber的 lastEffect 先push进去
		// 因为这里是 遍历到最底层往上走到 所以 执行顺序是 先执行 子组件的销毁回调函数 再执行 副组件的 销毁回调函数
		// 等所以销毁函数执行完后 再 执行子组件的 create 副作用函数 再执行 父组件的
		// 看下面 例子3
		finishedWork.flags &= ~PassiveEffect;
	}

	if ((flags & Ref) !== NoFlags && tag === HostComponent) {
		if (current !== null) {
			safelyDetachRef(current);
		}
	}
	if ((flags & Visibility) !== NoFlags && tag === OffscreenComponent) {
		const isHidden = finishedWork.pendingProps.mode === 'hidden';
		hideOrUnhideAllChildren(finishedWork, isHidden);
		finishedWork.flags &= ~Visibility;
	}
};

// 寻找根host节点，考虑到Fragment，可能存在多个
function findHostSubtreeRoot(
	finishedWork: FiberNode,
	callback: (hostSubtreeRoot: FiberNode) => void
) {
	let hostSubtreeRoot: FiberNode | null = null;
	let node = finishedWork;
	while (true) {
		if (node.tag === HostComponent) {
			if (hostSubtreeRoot === null) {
				// 还未发现 root，当前就是
				hostSubtreeRoot = node;
				callback(node);
			}
		} else if (node.tag === HostText) {
			if (hostSubtreeRoot === null) {
				// 还未发现 root，text可以是顶层节点
				callback(node);
			}
		} else if (
			node.tag === OffscreenComponent &&
			node.pendingProps.mode === 'hidden' &&
			node !== finishedWork
		) {
			// 隐藏的OffscreenComponent跳过
		} else if (node.child !== null) {
			node.child.return = node;
			node = node.child;
			continue;
		}

		if (node === finishedWork) {
			return;
		}

		while (node.sibling === null) {
			if (node.return === null || node.return === finishedWork) {
				return;
			}

			if (hostSubtreeRoot === node) {
				hostSubtreeRoot = null;
			}

			node = node.return;
		}

		// 去兄弟节点寻找，此时当前子树的host root可以移除了
		if (hostSubtreeRoot === node) {
			hostSubtreeRoot = null;
		}

		node.sibling.return = node.return;
		node = node.sibling;
	}
}

function hideOrUnhideAllChildren(finishedWork: FiberNode, isHidden: boolean) {
	findHostSubtreeRoot(finishedWork, (hostRoot) => {
		const instance = hostRoot.stateNode;
		if (hostRoot.tag === HostComponent) {
			isHidden ? hideInstance(instance) : unhideInstance(instance);
		} else if (hostRoot.tag === HostText) {
			isHidden
				? hideTextInstance(instance)
				: unhideTextInstance(instance, hostRoot.memoizedProps.content);
		}
	});
}

function safelyDetachRef(current: FiberNode) {
	const ref = current.ref;
	if (ref !== null) {
		if (typeof ref === 'function') {
			ref(null);
		} else {
			ref.current = null;
		}
	}
}

const commitLayoutEffectsOnFiber = (
	finishedWork: FiberNode,
	root: FiberRootNode
) => {
	const { flags, tag } = finishedWork;

	if ((flags & Ref) !== NoFlags && tag === HostComponent) {
		// 绑定新的ref
		safelyAttachRef(finishedWork);
		finishedWork.flags &= ~Ref;
	}
};

function safelyAttachRef(fiber: FiberNode) {
	const ref = fiber.ref;
	if (ref !== null) {
		const instance = fiber.stateNode;
		if (typeof ref === 'function') {
			ref(instance);
		} else {
			ref.current = instance;
		}
	}
}

export const commitMutationEffects = commitEffects(
	'mutation',
	MutationMask | PassiveMask,
	commitMutationEffectsOnFiber
);

export const commitLayoutEffects = commitEffects(
	'layout',
	LayoutMask,
	commitLayoutEffectsOnFiber
);

/**
 * 难点在于目标fiber的hostSibling可能并不是他的同级sibling
 * 比如： <A/><B/> 其中：function B() {return <div/>} 所以A的hostSibling实际是B的child
 * 实际情况层级可能更深
 * 同时：一个fiber被标记Placement，那他就是不稳定的（他对应的DOM在本次commit阶段会移动），也不能作为hostSibling
 */
function gethostSibling(fiber: FiberNode) {
	let node: FiberNode = fiber;
	findSibling: while (true) {
		while (node.sibling === null) {
			// 如果当前节点没有sibling，则找他父级sibling
			const parent = node.return;
			if (
				parent === null ||
				parent.tag === HostComponent ||
				parent.tag === HostRoot
			) {
				// 没找到
				return null;
			}
			node = parent;
		}
		node.sibling.return = node.return;
		// 向同级sibling寻找
		node = node.sibling;

		while (node.tag !== HostText && node.tag !== HostComponent) {
			// 找到一个非Host fiber，向下找，直到找到第一个Host子孙
			if ((node.flags & Placement) !== NoFlags) {
				// 这个fiber不稳定，不能用
				continue findSibling;
			}
			if (node.child === null) {
				continue findSibling;
			} else {
				node.child.return = node;
				node = node.child;
			}
		}

		// 找到最有可能的fiber
		if ((node.flags & Placement) === NoFlags) {
			// 这是稳定的fiber，就他了
			return node.stateNode;
		}
	}
}

function commitPassiveEffect(
	fiber: FiberNode,
	root: FiberRootNode,
	type: keyof PendingPassiveEffects // 表示  type为 unMount 和 update 中的一个
) {
	// update unmount
	if (
		fiber.tag !== FunctionComponent ||
		(type === 'update' && (fiber.flags & PassiveEffect) === NoFlags)
	) {
		return;
	}
	const updateQueue = fiber.updateQueue as FCUpdateQueue<any>;
	if (updateQueue !== null) {
		if (updateQueue.lastEffect === null) {
			console.error('当FC存在PassiveEffect flag时，不应该不存在effect');
		}
		root.pendingPassiveEffects[type].push(updateQueue.lastEffect as Effect);
	}
}

function commitHookEffectList(
	flags: Flags,
	lastEffect: Effect,
	callback: (effect: Effect) => void
) {
	// 当第一次执行的时候 effect 表示最后一个 effect
	let effect = lastEffect.next as Effect; // 获取第一个Effect

	do {
		// 先执行第一个 effect
		if ((effect.tag & flags) === flags) {
			// 表示当前effect.tag 符合执行的条件时 才执行
			callback(effect);
		}
		effect = effect.next as Effect;
	} while (effect !== lastEffect.next); // 执行完最后一个就跳出
}

// 表示  调度器遍历 root.pendingPassiveEffects.unmount 调用 commitHookEffectListUnmount  然后将 里面每个tag为Passive 的 effect的 destroy 执行一遍
export function commitHookEffectListUnmount(flags: Flags, lastEffect: Effect) {
	// 传入flags Passive
	commitHookEffectList(flags, lastEffect, (effect) => {
		const destroy = effect.destroy;
		if (typeof destroy === 'function') {
			destroy();
		}
		effect.tag &= ~HookHasEffect; // 执行完后 删除 HookHasEffect 标记 以免 后面 执行 多次
	});
}

// 这个函数表示 将 	pendingPassiveEffects.update 里面所以 标记为Passive | HookHasEffect (:即该Effect 需要执行副作用)的effect的 destroy 先执行一遍
export function commitHookEffectListDestroy(flags: Flags, lastEffect: Effect) {
	commitHookEffectList(flags, lastEffect, (effect) => {
		const destroy = effect.destroy;
		if (typeof destroy === 'function') {
			destroy();
		}
	});
}

// 这个函数表示 将 	pendingPassiveEffects.update 里面所以 标记为Passive | HookHasEffect (:即该Effect 需要执行副作用)的effect的 create 先执行一遍
// 然后执行create 的函数结果 赋值给 effect.destroy
export function commitHookEffectListCreate(flags: Flags, lastEffect: Effect) {
	commitHookEffectList(flags, lastEffect, (effect) => {
		const create = effect.create;
		if (typeof create === 'function') {
			effect.destroy = create(); // 重新赋值
		}
	});
}

function recordHostChildrenToDelete(
	childrenToDelete: FiberNode[],
	unmountFiber: FiberNode
) {
	// 1. 找到第一个插入的 host类型的 fiber节点
	const lastOne = childrenToDelete[childrenToDelete.length - 1];
	// lastOne最后一个兄弟节点
	if (!lastOne) {
		// 如果之前没插入过 就push
		childrenToDelete.push(unmountFiber);
	} else {
		// childrenToDelete 里已经有值了 那就看当前 unmountFiber 是不是 他的的兄弟节点 是的话就插入
		let node = lastOne.sibling;
		while (node !== null) {
			if (unmountFiber === node) {
				childrenToDelete.push(unmountFiber);
			}
			// 这里为什么要 将他的兄弟节点全部加入呢？ 而且commitNestedComponent 函数处理他的兄弟节点也会走到这
			// 可能要处理的情况是 兄弟节点是一个函数组件 函数组件节点 下层对应的dom 是和 他们同级的 所以也要删除
			// <div><div><app><app><span><span> 这种情况
			node = node.sibling;
		}
		// 当这个循环走完后 他的兄弟节点 都已经加入到 childrenToDelete 数组中了
		// 后面执行这个函数的时候 lastOne已经指向 最好一个兄弟节点了 lastOne.sibling == null了 就不会push；
	}

	// 2. 每找到一个 host节点，判断下这个节点是不是 1 找到那个节点的兄弟节点
}

// childToDelete 是 要删除的fiber
// <div>
// 	<child />
// 	<h1></h1>
// 	23
// 	<div></div>
// </div>;
// childToDelete 是 要删除的fiber 需要找到app 向下找到的dom
// <app>
// <div>
// <child />
// <h1></h1>
// 23
// </div>
// </app>;

// 遍历 处理该fiber树中的每一个fiber 对fiber 不同类型做不同处理
// 对于FC，需要处理useEffect unmout执行、解绑ref
// 对于HostComponent，需要解绑ref
// 对于子树的根HostComponent，需要移除DOM
// 所以需要实现「遍历ChildDeletion子树」的流程
// 上面流程 需要递归实现 自己fiber要处理 子fiber 也要处理
function commitDeletion(childToDelete: FiberNode, root: FiberRootNode) {
	const rootChildrenToDelete: FiberNode[] = []; // 保存着 childToDelete 下面第一层 host类型的fiber 即div span 这些
	// 然后把这些节点从childToDelete的parent dom 树中删除 一层：指的是 所以兄弟 div 都要删除

	// 递归树 每次遍历到 一个fiber 就调用一次 callback  onCommitUnmount 传回需要删除的fiber
	commitNestedComponent(childToDelete, (unmountFiber) => {
		// 根据需要删除的fiber的类型 做不同的是
		switch (unmountFiber.tag) {
			case HostComponent:
				// 普通div节点
				// 需要 解梆 ref
				// 是一个host类型Fiber 根据一定条件 将unmountFiber插入 rootChildrenToDelete
				recordHostChildrenToDelete(rootChildrenToDelete, unmountFiber);
				safelyDetachRef(unmountFiber);
				return;
			case HostText:
				// 文本节点
				recordHostChildrenToDelete(rootChildrenToDelete, unmountFiber);
				return;
			case FunctionComponent:
				//
				// 函数节点
				// useEffect 清理函数的 处理
				// 将 这些要卸载的组件的 fiber对应的 lastEffect 所以的 hook 都加入到 root.pendingPassiveEffects.unmount 里面
				// 因为卸载dom 执行药先执行 里面相关的 hook 的卸载 函数
				commitPassiveEffect(unmountFiber, root, 'unmount'); // 这里父fiber的 lastEffect 先push进去
				// 因为这里是从 上往下遍历 所以 执行 卸载回调函数的时候 是先执行父组件的 再执行子组件的
				return;
			default:
				if (true) {
					console.warn('未处理的unmount类型', unmountFiber);
				}
		}
	});

	// 情况一
	// const child = <h1></h1>;
	// const parent = <child></child>
	// 当要删除 parent 节的时候 需要 往下遍历 对每一个节点执行  对应操作 用时也要找到 第一个为host类型的 节点 并且后面 将他从dom树中删除
	// 因为 这个commitHookDeletion 函数 每次遍历到一个节点就会调用这个函数 如果最顶级的节点是 host 类型的话就保存下来  表面该节点 就是 childToDelete
	// 保存第一个为Host类型的 不管是 HostText 还是 HostComponent 的 节点 删除他

	// 情况二 childToDelete 下面可能有多个 类型为host 的根节点
	// const child = <><h1></h1><h1></h1></>;
	// const parent = <child></child>
	// 此时 rootHostNode 变成了 2个 需要将两个h1的dom 从 dom数树中移除

	// 移除rootChildrenToDelete 里面的dom 从hostParent 中移除
	if (rootChildrenToDelete.length) {
		// 找到 需要删除 fiber树的 最顶端的fiber 的父 dom
		// 然后 将rootChildrenToDelete 里面的 fiber 对应的 dom 都删除
		// 因为childToDelete 可能是一个 函数组件 然后 比如这样 <><div>></div><span></span</>
		// 这样的话 就有多个 dom 需要被从hostParent 中移除
		const hostParent = getHostParent(childToDelete);
		if (hostParent !== null) {
			// 当是这种情况的时候 <div><div><app><app><span><span> node 为app的Fiber节点 node.stateNode 是为null的 是不是得往下找 到对应的DOm？？？
			rootChildrenToDelete.forEach((node) => {
				// 这里不能满足 测试4 需要 判断node 类型 如果是函数组件 需要继续往下走 Dom  同时需要 考虑多节点情况
				removeChild(node.stateNode, hostParent);
			});
		}
	}

	// 断开链接
	childToDelete.return = null;
	childToDelete.child = null;
}

function commitNestedComponent(
	root: FiberNode,
	onCommitUnmount: (fiber: FiberNode) => void
) {
	let node = root;
	// 这个过程 和 beginWork 和 compleWork 差不多
	while (true) {
		// 当便利一个fiber的时候 就对他执行一次性 卸载操作

		onCommitUnmount(node);

		if (node.child !== null) {
			// 向下遍历
			node.child.return = node;
			node = node.child;
			continue;
		}

		if (node === root) {
			// 终止条件
			return;
		}
		// 走到这 说明 当前分支 走到最深了
		// 判断有没有兄弟节点 没有则向上归
		while (node.sibling === null) {
			if (node.return === null || node.return === root) {
				// 归到顶了
				return;
			}
			// 向上归
			node = node.return;
		}
		// 有兄弟节点的话 再去出来兄弟节点
		node.sibling.return = node.return;
		node = node.sibling;
	}
}

const commitPlacement = (finishedWork: FiberNode) => {
	if (true) {
		console.warn('执行Placement操作', finishedWork);
	}
	// parent DOM
	// 找到 fiber 对应的 父dom
	const hostParent = getHostParent(finishedWork);

	// host sibling 找需要移动的Fiber A 的第一个没有被标记 Placement的兄弟节点  B    将A插到B前面就行
	// 因为更新后的 fiber 本来 就是按照 更新后的ui的顺序排列的  只是对应的Dom 没有移动 或者插入
	// getHostSibling 这个函数不用死去理解 知道是找没有副作用的兄弟节点就行了
	const sibling = getHostSibling(finishedWork);

	// finishedWork ~~ DOM append parent DOM
	if (hostParent !== null) {
		// 因为是从 底层 往上找的 所以只需要插入 上一层 父dom 就行了
		// 不分 首次渲染 和 更新 首次渲染
		// 找到 finishedWork 对应的dom  插入到 hostParent 中
		insertOrAppendPlacementNodeIntoContainer(finishedWork, hostParent, sibling);
	}
};

// 这个不用死去理解 知道是找 兄弟节点继续了
function getHostSibling(fiber: FiberNode) {
	let node: FiberNode = fiber;

	findSibling: while (true) {
		// Adiv是我们标记要移动的节点 但他是在函数组件里面 需要将ADiv 拆入在Bdiv前 那就需要向上找
		//     // 情况2
		// <App/><Bdiv/>
		// function App() {
		//   return <Adiv/>;
		// }
		// 如果 没有兄弟节点了那就向上找父节点的兄弟节点
		// 这里是未来兼容情况二
		while (node.sibling === null) {
			// 如果 node没有兄弟节点
			const parent = node.return;

			if (
				parent === null ||
				parent.tag === HostComponent ||
				parent.tag === HostRoot
			) {
				// 这里表示 不满足情况二 那就是单节点 直接返回null 就可以了
				return null;
			}
			// 走到这说明 node 是在 函数组件或类组件里面 那就 将node复为 parent 然后去找parent的sibling
			node = parent;
		}

		node.sibling.return = node.return; // 为了重新保持一下关系 别出bug了

		node = node.sibling;

		// 情况一：
		//     Adiv是需要移动的dom B是函数组件 那就需要往下找对应的Dom
		// <Adiv/><B/>
		// function B() {
		//   return <div/>;
		// }
		while (node.tag !== HostText && node.tag !== HostComponent) {
			if ((node.flags & Placement) !== NoFlags) {
				// 如果该fiber 也是需要移动的那就 跳出findSibling循环 去找下一个兄弟节点
				continue findSibling;
			}
			if (node.child === null) {
				// 如果没有子节点了 也都不满足条件 那就跳出findSibling循环 去找下一个兄弟节点
				continue findSibling;
			} else {
				// 如果是类组件或者函数组件的话 向下遍历 继续找
				node.child.return = node;
				node = node.child;
			}
		}

		// 走到这表示 该node 是一个 普通节点 有对应的dom
		// 再判断 该fiber是不是稳定的 如果该fiber 没有被标记为 Placement 就将该 dom返回 后续 插入到该dom前面就行
		if ((node.flags & Placement) === NoFlags) {
			return node.stateNode;
		}
	}
}

function getHostParent(fiber: FiberNode): Container | null {
	let parent = fiber.return;

	while (parent) {
		const parentTag = parent.tag;
		// HostComponent HostRoot
		if (parentTag === HostComponent) {
			// 如果是 父节点是 div 这种 就直接返回 父dom
			return parent.stateNode as Container;
		}
		if (parentTag === HostRoot) {
			// 如果是 他的 父节点是 根节点 那就返回 根节点的 容器
			// hostRootFiber.stateNode 指向 root  root.container 指向容器
			return (parent.stateNode as FiberRootNode).container;
		}
		// 否则是 函数组件 或者 其他组件 就继续往上找
		parent = parent.return;
	}
	if (true) {
		console.warn('未找到host parent');
	}
	return null;
}

// finishedWork 这个节点 可能是 函数组件 或者 类组件 或者 普通组件
// 如果是 函数组件Fiber 那就需要向下找到他对应的dom
function insertOrAppendPlacementNodeIntoContainer(
	finishedWork: FiberNode,
	hostParent: Container,
	before?: Instance
) {
	// fiber host
	if (finishedWork.tag === HostComponent || finishedWork.tag === HostText) {
		if (before) {
			//insertChildToContainer(A, hostParent, B);
			// hostParent.insertBefore(A, B) B是已经存在hostParent的结构中的 将A插入B的前面
			// 因为更新后的 fiber 本来 就是按照 更新后的ui的顺序排列的  只是对应的Dom 没有移动 或者插入
			insertChildToContainer(finishedWork.stateNode, hostParent, before);
		} else {
			// 如果直接子节点是 div 或文本那就直接插入
			appendChildToContainer(hostParent, finishedWork.stateNode);
		}

		return;
	}
	const child = finishedWork.child;
	if (child !== null) {
		// 如果不是的话 函数组件的话 那就往下找 到第一个是div或文本的节点 插入 同时将 他的兄弟节点也插入hostParent
		insertOrAppendPlacementNodeIntoContainer(child, hostParent);
		let sibling = child.sibling;

		// 因为 函数组件里面 可能  是 <> <div></div> <div></div> </> 直接 包裹了 多个 子节点 所以需要遍历 兄弟节点
		while (sibling !== null) {
			insertOrAppendPlacementNodeIntoContainer(sibling, hostParent);
			sibling = sibling.sibling;
		}
	}
}

// tml
// Copy Code
// <div id="parent">
//   <div id="C"></div>
//   <div id="D"></div>
//   <div id="B"></div> <!-- 参考节点 B -->
//   <div id="E"></div>
// </div>
// 执行 parent.insertBefore(A, B) 后，结构变为：

// html
// Copy Code
// <div id="parent">
//   <div id="C"></div>
//   <div id="D"></div>
//   <div id="A"></div> <!-- A 插入到 B 前 -->
//   <div id="B"></div>
//   <div id="E"></div>
// </div>
// ⚠️ 注意事项
// ‌B 必须是 parent 的直接子节点‌，否则会抛出错误。
// 如果 ‌B 为 null‌，insertBefore 会将 A 插入到父节点末尾（效果等同于 parent.appendChild(A)）。
// 若 A 已存在于文档中，它会被‌移动‌到新位置，而非复制。
// 总结：‌A 在前，B 在后‌。 且B必须存在 在原先的结构中

// 例子3
// function App() {
//   const [num, updateNum] = useState(0);
//   useEffect(() => {
//     console.log('App mount');
//   }, []);

//   useEffect(() => {
//     console.log(' App num change create', num);
//     return () => {
//       console.log('App num change destroy', num);
//     };
//   }, [num]);

//   return (
//     <div onClick={() => updateNum(num + 1)}>
//       <Child num={num} />
//     </div>
//   );
// }

// function Child({ num }) {
//   useEffect(() => {
//     console.log('Child mount');
//     return () => console.log('Child unmount');
//   }, [num]);

//   return <Sun num={num} />;
// }

// function Sun({ num }) {
//   useEffect(() => {
//     console.log('sun mount');
//     return () => console.log('sun unmount');
//   }, [num]);
//   return 'sun';
// }

// const root = ReactDOM.createRoot(document.getElementById('root'));
// root.render(<App />);
// 点击的执行顺序是：
// sun unmount
// index.js:96 Child unmount
// index.js:82 App num change destroy 0
// index.js:104 sun mount
// index.js:95 Child mount
// index.js:80  App num change create 1
